# -*- coding: utf-8 -*-

import ConfigParser
from web.utils import Storage

class Config(object):
    def __init__(self, f = None):
        self.config = ConfigParser.SafeConfigParser()
        self.file = "wrTorrent.py.cfg"
        self.protocol = "scgi"
        self.url = "scgi://127.0.0.1:5000"
        self.domain = "127.0.0.1:8080"
        self.multicall = 1
        if not f is None:
            self.file = f
            self.load()

    def open(self):
        try:
            fname = open(self.file,"r")
        except IOError, v:
            print v
            fname = open(self.file,"w")
            fname.close()
            fname = open(self.file,"r")
        self.config.readfp(fname)
        fname.close()

    def close(self):
        fname = open(self.file,"w")
        self.config.write(fname)
        fname.close()

    def load(self):
        self.open()
        if not "rtorrent" in self.config.sections():
            self.config.add_section("rtorrent")
        try:
            self.protocol = self.config.get("rtorrent", "protocol")
        except ConfigParser.Error, v:
            print "Config error:", v
            self.config.set("rtorrent", "protocol", "scgi")
        try:
            self.url = self.config.get("rtorrent", "url")
        except ConfigParser.Error, v:
            print "Config error:", v
            self.config.set("rtorrent", "url", "scgi://127.0.0.1:5000")
        if not "wrtorrent.py" in self.config.sections():
            self.config.add_section("wrtorrent.py")
        try:
            self.domain = self.config.get("wrtorrent.py", "domain")
        except ConfigParser.Error, v:
            print "Config error:", v
            self.config.set("wrtorrent.py", "domain", "127.0.0.1:8080")
        try:
            self.multicall = int(self.config.get("wrtorrent.py", "multicall"))
        except ConfigParser.Error, v:
            print "Config error:", v
            self.config.set("wrtorrent.py", "multicall", "1")
        self.close()

    def save(self):
        self.config.set("rtorrent", "protocol", self.protocol)
        self.config.set("rtorrent", "url", self.url)
        self.config.set("wrtorrent.py", "domain", self.domain)
        self.config.set("wrtorrent.py", "multicall", str(self.multicall))
        self.close()

class Torrent(object):
    """ Class create torrent object and load info """

    def __init__(self, server, hash = None, name = None,
                        size = None, completed_bytes = None, message = None,
                        directory = None, ratio = None, peer_exchange = None,
                        peers_complete = None, peers_connected = None,
                        peers_not_connected = None, priority = None,
                        creation_date = None, is_open = None, active = None,
                        complete = None, up_total = None, down_rate = None,
                        up_rate = None, status = None, chunk_size = None):
        self.server = server
        self.hash = hash
        self.name = name
        self.size = size
        self.completed_bytes = completed_bytes
        self.message = message
        self.directory = directory
        self.ratio = ratio
        self.peer_exchange = peer_exchange
        self.peers_complete = peers_complete
        self.peers_connected = peers_connected
        self.peers_not_connected = peers_not_connected
        self.priority = priority
        self.creation_date = creation_date
        self.is_open = is_open
        self.active = active
        self.complete = complete
        self.status = status
        self.up_total = up_total
        self.down_rate = down_rate
        self.up_rate = up_rate
        self.chunk_size = chunk_size
        if hash is not None:
            if name is None:
                self.name = self.get_name()
            if chunk_size is None:
                self.chunk_size = self.get_chunk_size()
            if size is None:
                #self.size = self.get_size_bytes()
                # Fixed rtorrent bug
                self.size = self.get_size_chunks()*self.chunk_size
            if completed_bytes is None:
                #self.completed_bytes = self.get_completed_bytes()
                # Fixed bug again
                self.completed_bytes = self.get_completed_chunks()*self.chunk_size
            if message is None:
                self.message = self.get_message()
            if directory is None:
                self.directory = self.get_directory()
            if ratio is None:
                self.ratio = self.get_ratio()
            if peer_exchange is None:
                self.peer_exchange = self.get_peer_exchange()
            if peers_complete is None:
                self.peers_complete = self.get_peers_complete()
            if peers_connected is None:
                self.peers_connected = self.get_peers_connected()
            if peers_not_connected is None:
                self.peers_not_connected = self.get_peers_not_connected()
            if priority is None:
                self.priority = self.get_priority()
            if creation_date is None:
                self.creation_date = self.get_creation_date()
            if is_open is None:
                self.is_open = self.get_is_open()
            if active is None:
                self.active = self.get_is_active()
            if complete is None:
                self.complete = self.get_complete()
            if status is None:
                if self.is_open == 0 or self.active == 0: self.status = 0
                elif self.complete == 0: self.status = 1
                else: self.status = 2
            if up_total is None:
                self.up_total = self.get_up_total()
            if down_rate is None:
                self.down_rate = self.get_down_rate()
            if up_rate is None:
                self.up_rate = self.get_up_rate()

    # Info
    def get_name(self):
        try:
            name = self.server.d.get_name(self.hash)
        except:
            name = ""
        return name

    def get_size_bytes(self):
        return self.server.d.get_size_bytes(self.hash)

    def get_completed_bytes(self):
        return self.server.d.get_completed_bytes(self.hash)

    def get_message(self):
        return self.server.d.get_message(self.hash)

    def get_directory(self):
        try:
            directory = self.server.d.get_directory(self.hash)
        except:
            directory = ""
        return directory

    def get_ratio(self):
        return self.server.d.get_ratio(self.hash)

    def get_peer_exchange(self):
        return self.server.d.get_peer_exchange(self.hash)

    def get_peers_complete(self):
        return self.server.d.get_peers_complete(self.hash)

    def get_peers_connected(self):
        return self.server.d.get_peers_connected(self.hash)

    def get_peers_not_connected(self):
        return self.server.d.get_peers_not_connected(self.hash)

    def get_priority(self):
        return self.server.d.get_priority(self.hash)

    def get_creation_date(self):
        return self.server.d.get_creation_date(self.hash)

    def get_is_open(self):
        return self.server.d.is_open(self.hash)

    def get_is_active(self):
        return self.server.d.is_active(self.hash)

    def get_complete(self):
        return self.server.d.get_complete(self.hash)

    def get_up_total(self):
        return self.server.d.get_up_total(self.hash)

    def get_down_rate(self):
        return self.server.d.get_down_rate(self.hash)

    def get_up_rate(self):
        return self.server.d.get_up_rate(self.hash)

    def get_size_chunks(self):
        return self.server.d.get_size_chunks(self.hash)

    def get_completed_chunks(self):
        return self.server.d.get_completed_chunks(self.hash)

    def get_chunk_size(self):
        return self.server.d.get_chunk_size(self.hash)

    # Actions
    def open(self):
        return self.server.d.open(self.hash)

    def close(self):
        return self.server.d.close(self.hash)

    def erase(self):
        return self.server.d.erase(self.hash)

    def __str__(self):
        if self.name is not None:
            return self.name.encode("utf8")
        elif self.hash is not None:
            return self.hash
        else: return self

class File(object):
    """ Class create object for file in torrent """

    def __init__(self, server, hash = None, index = None, chunk_size = None,
                path = None, depth = None, is_open = None, priority = None,
                size_bytes = None, completed_chunks = None, size_chunks = None):
        self.server = server
        self.hash = hash
        self.index = index
        self.chunk_size = chunk_size
        self.path = path
        self.depth = depth
        #self.is_open = is_open
        self.priority = priority
        self.size_bytes = size_bytes
        self.completed_chunks = completed_chunks
        self.size_chunks = size_chunks
        if hash is not None and index is not None:
            if chunk_size is None:
                self.chunk_size = self.get_chunk_size()
            if path is None:
                self.path = self.get_path()
            if depth is None:
                self.depth = self.get_path_depth()
            #if is_open is None:
            #    self.is_open = self.get_is_open()
            if priority is None:
                self.priority = self.get_priority()
            if completed_chunks is None:
                self.completed_chunks = self.get_completed_chunks()
            if size_chunks is None:
                self.size_chunks = self.get_size_chunks()
            if size_bytes is None:
                #self.size_bytes = self.get_size_bytes()
                self.size_bytes = self.chunk_size*self.size_chunks
        if (not self.path is None) and (not self.depth is None):
            self.path_str = self.path[self.depth-1]

    # Info
    def get_path(self):
        return self.server.f.get_path_components(self.hash, self.index)

    def get_path_depth(self):
        return self.server.f.get_path_depth(self.hash, self.index)

    def get_is_open(self):
        return self.server.f.is_open(self.hash, self.index)

    def get_priority(self):
        return self.server.f.get_priority(self.hash, self.index)

    def get_size_bytes(self):
        return self.server.f.get_size_bytes(self.hash, self.index)

    def get_completed_chunks(self):
        return self.server.f.get_completed_chunks(self.hash, self.index)

    def get_size_chunks(self):
        return self.server.f.get_size_chunks(self.hash, self.index)

    def get_chunk_size(self):
        return self.server.d.get_chunk_size(self.hash)

    def __str__(self):
        if self.path is not None:
            return self.path_str.encode("utf8")
        else: return self

class Server(object):
    """ General class """

    def __init__(self, config):
        self.config = config

    def connect(self):
        """ Connect to server, set "self.rt" """
        if self.config.protocol == "scgi":
            import xmlrpc2scgi as xs
            from xmlrpclib import Error
            self.rt = xs.RTorrentXMLRPCClient(self.config.url)
        elif self.config.protocol == "xmlrpc":
            from xmlrpclib import ServerProxy, Error
            self.rt = ServerProxy(self.config.url)

    # Torrents function
    def list(self, mode = "default"):
        """ Load torrents list """
        result = []
        if self.config.multicall:
            list = self.rt.d.multicall(mode, "d.get_hash=", "d.get_name=",
                    "d.get_size_bytes=", "d.get_completed_bytes=",
                    "d.get_message=", "d.get_directory=", "d.get_ratio=",
                    "d.get_peer_exchange=", "d.get_peers_complete=",
                    "d.get_peers_connected=", "d.get_peers_not_connected=",
                    "d.get_priority=", "d.get_creation_date=", "d.is_open=",
                    "d.is_active=", "d.get_complete=", "d.get_up_total=",
                    "d.get_size_chunks=", "d.get_chunk_size=",
                    "d.get_completed_chunks=")
            for torrent in list:
                result.append(Torrent(self.rt, torrent[0], torrent[1], torrent[17]*torrent[18],
                    torrent[19]*torrent[18], torrent[4], torrent[5], torrent[6],
                    torrent[7], torrent[8], torrent[9], torrent[10],
                    torrent[11], torrent[12], torrent[13], torrent[14],
                    torrent[15], torrent[16], torrent[18]))
        else:
            hashs = self.rt.download_list()
            for hash in hashs:
                result.append(Torrent(self.rt, hash))
        return result

    def open(self, hash):
        return self.rt.d.open(hash)

    def close(self, hash):
        return self.rt.d.close(hash)

    def start(self, hash):
        return self.rt.d.start(hash)

    def stop(self, hash):
        return self.rt.d.stop(hash)

    def erase(self, hash):
        return self.rt.d.erase(hash)

    def add(self, url):
        return self.rt.load(url)

    def add_start(self, url):
        return self.rt.load(url)

    def get_torrent(self, hash):
        return Torrent(self.rt, hash)

    def set_priority(self, hash, priority):
        priority = int(priority)
        old_priority = int(self.rt.d.get_priority(hash))
        if priority != old_priority:
            self.rt.d.set_priority(hash, priority)
        return 0

    # File functions
    def files(self, hash, chunk_size):
        result = []
        if self.config.multicall:
            list = self.rt.f.multicall(hash, "f.get_path=",
                        "f.get_path_components=", "f.get_path_depth=",
            #            "f.is_open=", "f.get_priority=",
                        "f.get_priority=",
                        "f.get_size_bytes=", "f.get_completed_chunks=",
                        "f.get_size_chunks=")
            i = 0
            for file in list:
                #result.append(File(self.rt, hash, file[0], file[1], file[2],
                #            file[3], file[4], file[5], file[6], i))
                result.append(File(self.rt, hash, i, chunk_size, file[0],
                              file[1], file[2], None, file[4]*chunk_size,
                              file[4], file[5]))
                i += 1
        else:
            files = self.rt.d.get_size_files(hash)
            i = 0
            while i < files:
                result.append(File(self.rt,  hash, i, chunk_size))
                i += 1
        return result

    def set_files_priority(self, hash, index, priority):
        index = int(index)
        priority = int(priority)-1
        old_priority = int(self.rt.f.get_priority(hash, index))
        if priority != old_priority:
            self.rt.f.set_priority(hash, index, priority)

    # Config functions
    def set_config(self):
        pass

class rTorrent_config(Storage):
    def __init__(self, rt):
        self.rt = rt

    def parse_help(self, name = "rtorrent_config_help"):
        result = {}
        f = open(name)
        c = "advanced"
        for line in f.readlines():
            if "[" in line:
                c = line[1:-2]
                result[c] = {}
            else:
                line = line.split(";")
                if len(line) == 4:
                    result[c][line[0]] = (line[1], line[2], line[3])
        f.close()
        return result

    def listMethods(self, methods, help):
        result = {}
        flag = 0
        for method in methods:
            if method[:4] == "set_":
                flag = 0
                method = method[4:]
                for c in help.keys():
                    if method in help[c].keys():
                        if not c in result.keys():
                            result[c] = {}
                        result[c][method] = []
                        result[c][method].append(help[c][method][0])
                        result[c][method].append(help[c][method][1])
                        result[c][method].append(help[c][method][2])
                        result[c][method].append(eval("self.rt.get_%s()" % method))
                        flag = 1
                        break
                if flag == 0:
                    if not "Advanced" in result.keys():
                            result["Advanced"] = {}
                    result["Advanced"][method] = [method, "", ""]
                    result["Advanced"][method].append(eval("self.rt.get_%s()" % method))
        return result
